package com.heyi.nettylong.client.handler;

import com.heyi.nettylong.client.config.ClientProperties;
import com.heyi.nettylong.client.listener.ChannelDataListener;
import com.heyi.nettylong.common.MessageHandler;
import com.heyi.nettylong.common.MessageRepository;
import com.heyi.nettylong.common.protobuf.Command;
import com.heyi.nettylong.common.protobuf.Message;
import com.heyi.nettylong.common.util.MessageUtil;
import com.heyi.nettylong.common.util.SpringBeanFactory;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.SimpleDateFormat;

/**
 * 处理心跳和连接的Handler
 *  @author dengfeng
 */
@Slf4j
public class HeartHandler extends SimpleChannelInboundHandler<Message.MessageBase> {
	private final DateFormat sf = new SimpleDateFormat("HH:mm:ss");

	private long ccTime = 0;//缓存发送时间 单位毫秒

	ClientProperties clientProperties;

	private final ChannelDataListener channelDataListener = SpringBeanFactory.getBean(ChannelDataListener.class);

	// 定义客户端没有收到服务端的pong消息的最大次数
	private static final int MAX_UN_REC_PONG_TIMES = 2;

	// 多长时间未请求后，发送心跳
	private static final int WRITE_WAIT_SECONDS = 5;//暂时未使用

	// 隔N秒后重连
	private static final int RE_CONN_WAIT_SECONDS = 5;//暂时未使用

	// 客户端连续N次没有收到服务端的pong消息  计数器
	private int unRecPongTimes = 0 ;
	/**
	 * @param clientProperties
	 */
	public HeartHandler(ClientProperties clientProperties) {
		this.clientProperties = clientProperties;
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent event = (IdleStateEvent) evt;
			if (event.state() == IdleState.READER_IDLE) {
				if(unRecPongTimes > 0) {
					log.info("-----netty 心跳超时{}次", unRecPongTimes);
				}
				if (unRecPongTimes < MAX_UN_REC_PONG_TIMES) {
					if (ctx.channel() != null && ctx.channel().isActive() && ctx.channel().isOpen()) {
						sendPingMsg(ctx);
						unRecPongTimes++;
						return;
					}
					log.info("-----netty连接状态异常[isActive={}],关闭连接", ctx.channel().isActive());
				}else{
					log.info("-----netty服务端心跳超时,关闭连接");
				}
				ctx.channel().close();
				if (channelDataListener != null) {
					channelDataListener.disconnected();
				}
			} else {
				super.userEventTriggered(ctx, evt);
			}
		}
	}

	/**
	 * 发送ping消息
	 * @param context
	 */
	protected void sendPingMsg(ChannelHandlerContext context) {
		ccTime = System.currentTimeMillis();
		context.writeAndFlush(
				MessageUtil.build(clientProperties.getClientId(), Command.CommandType.PING, String.valueOf(ccTime), clientProperties.getToken())
		);

	 	log.debug("发送心跳ping");
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, Message.MessageBase msg) {
		if(msg.getCmd().equals(Command.CommandType.PONG)){
			//接收到server发送的pong指令
			unRecPongTimes = 0;
			log.debug("收到pong");
		}else if(msg.getCmd().equals(Command.CommandType.PUSH_DATA)){
			if(channelDataListener != null){
				MessageHandler messageHandler = new ClientMessageHandler(ctx, msg, clientProperties.getToken());
				try {
					channelDataListener.receiveData(messageHandler);
				} catch (Exception e) {
					log.error("channelDataListener发生错误：" + e);
				}
			}
		}else if(msg.getCmd().equals(Command.CommandType.PUSH_DATA_BACK)){
			MessageRepository.put(msg);
		}else{
			log.error("收到未知消息【"+msg.getCmd()+"】："+ msg.getData());
		}
	}
}
